﻿using System.Text;

namespace MSHelpMe.ViewModels
{
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.ComponentModel;
    using System.Linq;
    using System.Xml.Linq;
    using BingService;

    public class MainViewModel : INotifyPropertyChanged
    {
        private const int MaxFlaggedItem = 1000;

        private readonly Dictionary<string, ItemViewModel> uriCheckes;

        public MainViewModel()
        {
            this.Items = new ObservableCollection<ItemViewModel>();
            this.FlaggedItems = new ObservableCollection<ItemViewModel>();
            this.uriCheckes = new Dictionary<string, ItemViewModel>();
        }

        /// <summary>
        /// A collection for ItemViewModel objects.
        /// </summary>
        public ObservableCollection<ItemViewModel> Items
        {
            get;
            private set;
        }

        /// <summary>
        /// 
        /// </summary>
        public ObservableCollection<ItemViewModel> FlaggedItems
        {
            get;
            private set;
        }

        private string queryText = "Enter your question here...";

        /// <summary>
        /// The query text.
        /// </summary>
        public string QueryText
        {
            get
            {
                return this.queryText;
            }
            set
            {
                this.queryText = value;
                NotifyPropertyChanged("QueryText");
            }
        }

        private uint totalFound;

        public uint TotalFound
        {
            get
            {
                return this.totalFound;
            }
            set
            {
                this.totalFound = value;
                NotifyPropertyChanged("TotalFound");
            }
        }

        private bool notVoted = true;

        public bool NotVoted
        {
            get
            {
                return this.notVoted;
            }
            set
            {
                this.notVoted = value;
                NotifyPropertyChanged("NotVoted");
            }
        }

        protected uint totalSearched;

        public uint TotalSearched
        {
            get
            {
                return this.totalSearched;
            }
            set
            {
                this.totalSearched = value;
                NotifyPropertyChanged("TotalSearch");
            }
        }

        public int LeftCount
        {
            get
            {
                return MaxFlaggedItem - this.FlaggedItems.Count;
            }
        }

        /// <summary>
        /// Creates and adds a few ItemViewModel objects into the Items collection.
        /// </summary>
        public void LoadData(string data)
        {
            // Load flagged items
            var doc = XDocument.Parse(data);

            if (doc.Root != null)
            {
                var flaggedNode = doc.Root.Element("flagged");

                if (flaggedNode != null)
                {
                    var nodes = from i in flaggedNode.Elements("result")
                                select i;

                    foreach (var node in nodes)
                    {
                        this.FlagItem(ItemViewModel.ParseResultElement(node));
                    }
                }

                var votedNode = doc.Root.Element("notvoted");

                if (votedNode != null)
                {
                    this.NotVoted = bool.Parse(votedNode.Value);
                }

                var totalSearchedNode = doc.Root.Element("searched");

                if (totalSearchedNode != null)
                {
                    this.TotalSearched = uint.Parse(totalSearchedNode.Value);
                }
            }
        }

        public string ToXml()
        {
            var sb = new StringBuilder();
            sb.Append("<root>");
            sb.AppendFormat("<notvoted>{0}</notvoted>", this.NotVoted);
            sb.AppendFormat("<searched>{0}</searched>", this.TotalSearched);

            sb.Append("<flagged>");

            foreach (var i in this.FlaggedItems)
            {
                sb.Append(i.ToXml());
            }

            sb.Append("</flagged>");
            sb.Append("</root>");

            return sb.ToString();
        }

        public event PropertyChangedEventHandler PropertyChanged;
        private void NotifyPropertyChanged(String propertyName)
        {
            if (null != PropertyChanged)
            {
                PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        public void ClearSearchResults()
        {
            App.ViewModel.Items.Clear();
            App.ViewModel.TotalFound = 0;
        }

        public bool AppendSearchResult(SearchResponse results)
        {
            this.TotalFound = 0;

            if (results == null)
            {
                return false;
            }

            if (results.Web == null)
            {
                return false;
            }

            this.TotalFound = results.Web.Total;

            if (this.totalFound == 0 || results.Web.Results == null)
            {
                return false;
            }

            var nodes = from i in results.Web.Results
                        select i;

            foreach (var node in nodes)
            {
                this.Items.Add(ItemViewModel.Create(node));
            }

            return true;
        }

        public void FlagItem(ItemViewModel item)
        {
            if (item.Flagged)
            {
                UnflagItem(item);
                return;
            }

            if (this.FlaggedItems.Count > MaxFlaggedItem)
            {
                return;
            }

            this.uriCheckes.Add(item.Uri, item);
            this.FlaggedItems.Add(item);

            this.NotifyItems(item.Uri);
            this.NotifyPropertyChanged("LeftCount");
        }

        public void UnflagItem(ItemViewModel item)
        {
            var flagged = this.uriCheckes[item.Uri];

            this.FlaggedItems.Remove(flagged);
            this.uriCheckes.Remove(flagged.Uri);

            flagged.NotifyFlagChanged();

            this.NotifyItems(flagged.Uri);
            this.NotifyPropertyChanged("LeftCount");
        }

        private void NotifyItems(string uri)
        {
            (from i in this.Items
             where i.Uri == uri
             select i).ToList().ForEach(i => i.NotifyFlagChanged());
        }

        public bool HasFlagged(ItemViewModel item)
        {
            return this.uriCheckes.ContainsKey(item.Uri);
        }
    }
}